package top.yoohome.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 验证相关工具类
 *
 * @author Johnny Zhang
 */
public class AuthUtil {

    /**
     * 中国大陆手机号长度 11位
     */
    private static final int CHINA_MOBILE_PHONE_SIZE = 11;

    /**
     * 中国大陆公民身份证长度 18位
     */
    private static final int CHINA_ID_CARD_NUMBER_SIZE = 18;

    /**
     * 正则表达式：手机号
     *
     *  2018年3月已知
     *  中国电信号段
     *       133,149,153,173,177,180,181,189,199
     *  中国联通号段
     *       130,131,132,145,155,156,166,175,176,185,186
     *  中国移动号段
     *       134(0-8),135,136,137,138,139,147,150,151,152,157,158,159,178,182,183,184,187,188,198
     *  其他号段
     *       14号段以前为上网卡专属号段，如中国联通的是145，中国移动的是147等等。
     *  虚拟运营商
     *       电信：1700,1701,1702
     *        移动：1703,1705,1706
     *       联通：1704,1707,1708,1709,171
     *  卫星通信
     *       148(移动) 1349
     */
    private static final String REGEX_CHINA_PHONE = "^[1](([3][0-9])|([4][579])|([5][469])|([6][6])|([7][35678])|([8][0-9])|([9][89]))[0-9]{8}$";

    /**
     * 正则表达式：验证邮箱
     */
    private static final String REGEX_EMAIL = "^([a-z0-9A-Z]+[-|.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";

    /**
     * 正则表达式：中国公民身份证
     *
     * 定义判别用户身份证号的正则表达式（15位或者18位，最后一位可以为字母）
     * 假设18位身份证号码:41000119910101123X  410001 19910101 123X
     * ^开头
     * [1-9] 第一位1-9中的一个      4
     * \\d{5} 五位数字           10001（前六位省市县地区）
     * (18|19|20)                19（现阶段可能取值范围18xx-20xx年）
     * \\d{2}                    91（年份）
     * ((0[1-9])|(10|11|12))     01（月份）
     * (([0-2][1-9])|10|20|30|31)01（日期）
     * \\d{3} 三位数字            123（第十七位奇数代表男，偶数代表女）
     * [0-9Xx] 0123456789Xx其中的一个 X（第十八位为校验值）
     * $结尾
     *
     * 假设15位身份证号码:410001910101123  410001 910101 123
     * ^开头
     * [1-9] 第一位1-9中的一个      4
     * \\d{5} 五位数字           10001（前六位省市县地区）
     * \\d{2}                    91（年份）
     * ((0[1-9])|(10|11|12))     01（月份）
     * (([0-2][1-9])|10|20|30|31)01（日期）
     * \\d{3} 三位数字            123（第十五位奇数代表男，偶数代表女），15位身份证不含X
     * $结尾
     */
    private static final String REGEX_ID_CARD =
            "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|"
            + "(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)";

    /**
     * 正则表达式：校验整数
     */
    private static final String REGEX_INT = "[0-9]*";

    /**
     * 校验中国大陆手机号
     *
     * @param phone 手机号
     * @return boolean 是否校验成功
     */
    public static boolean authPhone(String phone){
        if(phone.length() == CHINA_MOBILE_PHONE_SIZE){
            Pattern p = Pattern.compile(REGEX_CHINA_PHONE);
            Matcher m = p.matcher(phone);
            return m.matches();
        }
        return false;
    }

    /**
     * 校验邮箱
     *
     * @param email 邮箱地址
     * @return boolean 是否校验成功
     */
    public static boolean authEmail(String email) {
        return Pattern.matches(REGEX_EMAIL, email);
    }

    /**
     * 校验中国大陆公民身份证
     *
     * @param idNumber 身份证号 15位或18位
     * @return boolean 是否校验成功
     */
    public static boolean authidNumber(String idNumber) {
        if (idNumber == null || "".equals(idNumber)) {
            return false;
        }
        Pattern pattern = Pattern.compile(REGEX_ID_CARD);
        Matcher matcher = pattern.matcher(idNumber);
        // 校验18位身份证号,并判断第18位校验值
        if (matcher.matches()) {
            if (idNumber.length() == CHINA_ID_CARD_NUMBER_SIZE) {
                char[] charArray = idNumber.toCharArray();
                // 前十七位加权因子
                int[] idCardWi = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
                // 这是除以11后，可能产生的11位余数对应的验证码
                String[] idCardY = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
                int sum = 0;
                for (int i = 0; i < idCardWi.length; i++) {
                    int current = Integer.parseInt(String.valueOf(charArray[i]));
                    int count = current * idCardWi[i];
                    sum += count;
                }
                char idCardLast = charArray[17];
                int idCardMod = sum % 11;
                return idCardY[idCardMod].toUpperCase().equals(String.valueOf(idCardLast).toUpperCase());
            }
        }
        return matcher.matches();
    }

    /**
     * 校验整数（String类型）
     *
     * @param str 整数
     * @return 是否为整数
     */
    public static boolean authInt(String str) {
        if (str == null) {
            return false;
        }
        Pattern pattern = Pattern.compile(REGEX_INT);
        Matcher isNum = pattern.matcher(str);
        return isNum.matches();
    }
}
